Process Analysis Toolkit (PAT) 3.5 Help |
PAT only supports integer, Boolean and
integer arrays for the purpose of efficient verification.
However, advanced data structures (e.g., Stack, Queue, Hashtable and so on) are
necessary for some models. To support arbitrary data structures, PAT provides an
interface to create user defined data type by inheriting an abstract classes
ExpressionValue. The following is one simple example showing how to create a hashtable in
C#.
using System.Collections; //the namespace must be PAT.Lib, the class and method names can be
arbitrary /// Default constructor
without any parameter must be
implemented public
HashTable(Hashtable newTable)
{ public void Add(int key,
int value)
{ public int GetValue(int
key)
{ /// Return the string
representation of the hash
table.
return returnString; /// Return a deep clone of the hash
table /// Return the compact string representation of
the hash table.
string returnString =
"";
return returnString; } }
using
PAT.Common.Classes.Expressions.ExpressionClass;
namespace PAT.Lib {
public class
HashTable : ExpressionValue
{
public Hashtable
table;
public HashTable()
{
table = new Hashtable();
}
table = newTable;
}
if(!table.ContainsKey(key))
{
table.Add(key,
value);
}
}
public bool
ContainsKey(int key)
{
return
table.ContainsKey(key);
}
return (int)table[key];
}
/// This method
must be overriden
public
override string ToString()
{
string returnString =
"";
foreach (DictionaryEntry entry in table)
{
returnString += entry.Key + "=" + entry.Value +
",";
}
}
/// NOTE:
this must be a deep clone, shallow clone may lead to strange
behaviors.
///
This method must be
overriden
public
override ExpressionValue GetClone()
{
return new HashTable(new
Hashtable(table));
}
/// This
method must be overriden
/// Smart implementation of this method can reduce the state space and
speedup verification
public override string ExpressionID
{
get
{
foreach (DictionaryEntry entry in table)
{
returnString
+= entry.Key + "=" + entry.Value +
",";
}
}
}
Note the following requirements when you create your own data structure objects:
If your methods need to handle exceptional cases, you can throw PAT runtime exceptions as illustrated as the following example.
public static int StackPeek(int[] array) {
if (array.Length > 0)
return array[array.Length - 1];//throw PAT Runtime exception
throw new PAT.Common.Classes.Expressions.ExpressionClass.RuntimeException("Access an empty stack!");
}
To import the libraries in your model, users can using following syntax:
To declare the user defined types in your models, please use the following syntax:
To invoke the public methods in your models, please use the following syntax:
Note that there is no difference between user defined types and normal variables (e.g. var x =1;). Only when the process parameter is used as user defined types, it is user's responsibility to make sure that the correct variable type is passed in since most of PAT modules don't have explicit types. See the example below.
#import "PAT.Lib.Set";
var<Set>
set1;
Q() =
P(set1);
P(i) = initialize{i.Add(1);}-> ([i.GetSize() > 0] Skip);
Warning:
When the user defined data variable (declared as global variable) is used in conditions (if-then-else/guard/while-loop), the operation should be side-effect free. One example is the guard expression "i.GetSize() > 0" Otherwise the verification results may not be correct.
When user defined data structure is used as process parameter, if the parameter in the process updates the data structure, the verification/simulation maybe wrong and unexpected. For instance the following example, i is an object used in both branch of the choice operator, so the effect of executing add1 will stay even the actual branch selected is add2. In the simulator, you will find that after executing event add2, the value of set1 can become [1,2]. The root of this cause is the pointer problem. PAT will give warnings for such usage during parsing. It is user's responsibility to make sure the usage is correct.
#import "PAT.Lib.Set";
var<Set>
set1;
Q() =
P(set1);
P(i) = add1{i.Add(1);} -> Skip [] add2{i.Add(2);} -> Skip;